﻿using FxSuperCore.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace MemHack.Mem
{
	/// <summary>
	/// 内存页访问基类
	/// </summary>
	public abstract class MemByteAccessWrapper : IDisposable
	{
		protected MemoryHack mMemoryHack;

		protected PMEMORY_BASIC_INFORMATION32 mMemInfo;

		public virtual uint Length => this.mMemInfo.RegionSize;

		public MemByteAccessWrapper(MemoryHack memoryHack, PMEMORY_BASIC_INFORMATION32 memInfo)
		{
			this.mMemoryHack = memoryHack;
			this.mMemInfo = memInfo;
		}
		public virtual byte this[uint idx] => 0;

		public abstract void Dispose();
	}

	/// <summary>
	/// 内存页访问包装类(顺序访问性能较高，随机访问性能较差)
	/// </summary>
	public class MemPageByteWrapper : MemByteAccessWrapper
	{
		private uint mMaxMemSize => mMemoryHack.MaxOnceSearchMemSizePerThread;

		private byte[] mbytes;

		// 表示对应内存页映射的起始偏移
		private uint mMemGetStartIdx = 0;

		// 已经获取到的内存页中的内存长度
		private uint mMemGetLen = 0;

		public MemPageByteWrapper(MemoryHack memoryHack, PMEMORY_BASIC_INFORMATION32 memInfo):base(memoryHack, memInfo)
		{
			this.MoveToNextBytes(0);
		}

		private void MoveToNextBytes(uint idx)
		{
			mMemGetStartIdx = idx;
			uint getSize = Length - mMemGetStartIdx;
			mMemGetLen = getSize >= mMaxMemSize ? mMaxMemSize : getSize;
			mbytes = mMemoryHack.ReadBytes(mMemInfo.BaseAddress.ToInt64() + mMemGetStartIdx, (int)mMemGetLen);
		}

		public override byte this[uint idx]
		{
			get
			{
				if (idx >= Length)
				{
					throw new IndexOutOfRangeException("索引超出范围");
				}

				if (idx < mMemGetStartIdx || idx >= mMemGetStartIdx + mMemGetLen)
				{
					this.MoveToNextBytes(idx);
				}

				return mbytes[(int)(idx - mMemGetStartIdx)];
			}
		}

		public override void Dispose()
		{
			mbytes = null;
		}
	}

	public interface ISearchByte
	{
		void InitSearchBytes(byte[] searchBytes);

		uint[] SearchBytes(MemByteAccessWrapper byteAccess, byte[] searchBytes);

		uint[] SearchNumber(MemByteAccessWrapper byteAccess, byte[] searchBytes);

		void ExitSearchBytes(byte[] searchBytes);
	}

	public abstract class AbstractSeacher : ISearchByte
	{
		public abstract void InitSearchBytes(byte[] searchBytes);
		public abstract void ExitSearchBytes(byte[] searchBytes);
		public abstract uint[] SearchBytes(MemByteAccessWrapper byteAccess, byte[] searchBytes);
		public virtual uint[] SearchNumber(MemByteAccessWrapper byteAccess, byte[] searchBytes)
		{
			if (searchBytes == null || searchBytes.Length == 0)
			{
				throw new ArgumentException("搜索字节数不可为0");
			}
			LinkedList<uint> idxs = new LinkedList<uint>();
			int searchLen = searchBytes.Length;
			int seg = Math.Min(searchLen, 4);
			uint idx = 0;
			while (idx + searchLen <= byteAccess.Length)
			{
				bool isMatch = true;
				for (int i = 0; i < searchLen; i++)
				{
					if (byteAccess[(uint)(idx + i)] != searchBytes[i])
					{
						isMatch = false;
						break;
					}
				}

				if (isMatch)
				{
					idxs.AddLast(idx);
					idx += (uint)searchLen;
				}
				else
				{
					idx += (uint)seg;
					continue;
				}
			}

			return idxs.ToArray();
		}
	}

	/// <summary>
	/// Kmp搜索算法
	/// </summary>
	public class KmpByteSearcher : AbstractSeacher
	{
		public int[] Next { get; protected set; }

		public override void InitSearchBytes(byte[] searchBytes) => InitNext(searchBytes);

		private void InitNext(byte[] searchBytes)
		{
			Next = new int[searchBytes.Length];

			int i = 0;
			int j = -1;

			Next[0] = -1;

			while (i < searchBytes.Length - 1)
			{
				if (j == -1 || searchBytes[i] == searchBytes[j])
				{
					i++;
					j++;

					if (i > 0)
					{
						Next[i] = j;
					}
				}
				else
				{
					j = Next[j];
				}
			}
			//优化next数组
			for (int m = 0; m < Next.Length; m++)
			{
				int k = Next[m];
				if (Next[m] == -1)
					continue;

				if (searchBytes[m] == searchBytes[k])
				{
					Next[m] = Next[k];
				}
			}

		}

		protected virtual uint KmpSearchBytes(MemByteAccessWrapper byteAccess, byte[] searchBytes, uint startIdx)
		{
			// 原字节数组
			uint i = startIdx;
			// 待搜索字节数组
			int j = -1;

			while (i < byteAccess.Length)
			{
				if (j == -1 || byteAccess[i] == searchBytes[j])
				{
					i++;
					j++;

					if (j > searchBytes.Length - 1)
					{
						return i - (uint)j;
					}
				}
				else
				{
					j = Next[j];
				}
			}
			return uint.MaxValue;
		}

		public override uint[] SearchBytes(MemByteAccessWrapper byteAccess, byte[] searchBytes)
		{
			if (searchBytes == null || searchBytes.Length == 0)
			{
				throw new ArgumentException("搜索字节数不可为0");
			}
			LinkedList<uint> idxs = new LinkedList<uint>();

			uint startIdx = 0;
			while (startIdx < byteAccess.Length)
			{
				uint idx = KmpSearchBytes(byteAccess, searchBytes, startIdx);
				if (idx == uint.MaxValue)
				{
					break;
				}

				idxs.AddLast(idx);
				startIdx = idx + 1;
			}
			return idxs.ToArray();
		}

		public override void ExitSearchBytes(byte[] searchBytes)
		{
			Next = null;
		}
	}

	/// <summary>
	/// Sunday搜索算法
	/// </summary>
	public class SundaySearcher : AbstractSeacher
	{
		private int[] jumpTable;

		public override void InitSearchBytes(byte[] searchBytes)
		{
			int m = searchBytes.Length;
			// 构建跳跃表
			jumpTable = new int[256];
			for (int i = 0; i < 256; i++)
			{
				jumpTable[i] = m + 1;
			}
			for (int i = 0; i < m; i++)
			{
				jumpTable[searchBytes[i]] = m - i;
			}
		}

		protected virtual uint SundaySearchBytes(MemByteAccessWrapper byteAccess, byte[] searchBytes, uint startIdx)
		{
			uint n = byteAccess.Length;
			uint m = (uint)searchBytes.Length;
			uint index = startIdx;
			while (index <= n - m)
			{
				int i = 0;
				while (i < m && byteAccess[(uint)(index + i)] == searchBytes[i])
				{
					i++;
				}
				if (i == m)
				{
					return index; // 匹配成功，返回索引
				}
				else
				{
					if (index + m >= n)
					{
						return uint.MaxValue; // 匹配失败，超出字符串长度
					}
					else
					{
						index += (uint)jumpTable[byteAccess[index + m]]; // 跳跃到下一个位置
					}
				}
			}
			return uint.MaxValue;
		}

		public override uint[] SearchBytes(MemByteAccessWrapper byteAccess, byte[] searchBytes)
		{
			if (searchBytes == null || searchBytes.Length == 0)
			{
				throw new ArgumentException("搜索字节数不可为0");
			}
			LinkedList<uint> idxs = new LinkedList<uint>();

			uint startIdx = 0;
			while (startIdx < byteAccess.Length)
			{
				uint idx = SundaySearchBytes(byteAccess, searchBytes, startIdx);
				if (uint.MaxValue == idx)
				{
					break;
				}

				idxs.AddLast(idx);
				startIdx = idx + 1;
			}
			return idxs.ToArray();
		}

		public override void ExitSearchBytes(byte[] searchBytes)
		{
			jumpTable = null;
		}
	}


	public class MultiThreadSearch
	{
		private MemoryHack mMemHack;

		private SemaphoreSlim semaphore;

		private readonly object locker = new object();

		public MultiThreadSearch(MemoryHack memoryHack)
		{
			this.mMemHack = memoryHack;
			this.semaphore = new SemaphoreSlim(memoryHack.MaxSearchThreadNum);
		}

		public long[] Search(byte[] searchBytes, bool byteAlign, ulong startAddr = 0, ulong endAddr = ulong.MaxValue)
		{
			mMemHack.RefreshVirtualMemInfo();
			long startTime = CommonUtils.DatetimeToTimespan(DateTime.Now);
			LinkedList<long> searchRes = new LinkedList<long>();
			mMemHack.Searcher.InitSearchBytes(searchBytes);
			foreach (var memInfo in mMemHack.MemInfos)
			{
				if ((mMemHack.SearchMemProtectMode & memInfo.Protect) == 0)
				{
					continue;
				}

				if ((ulong)memInfo.BaseAddress.ToInt64() + memInfo.RegionSize < startAddr)
				{
					continue;
				}

				if ((ulong)memInfo.BaseAddress.ToInt64() > endAddr)
				{
					break;
				}

				semaphore.Wait();

				Task.Run(() =>
				{
					using (MemByteAccessWrapper byteWrapper = new MemPageByteWrapper(mMemHack, memInfo))
					{
						try
						{
							uint[] res;
							if (byteAlign)
							{
								res = mMemHack.Searcher.SearchNumber(byteWrapper, searchBytes);
							}
							else
							{
								res = mMemHack.Searcher.SearchBytes(byteWrapper, searchBytes);
							}

							lock (locker)
							{
								foreach (var idx in res)
								{
									searchRes.AddLast(memInfo.BaseAddress.ToInt64() + idx);
								}
							}
						}
						catch (Exception e)
						{
							mMemHack.Log($"搜索内存出错: [{e.Message}] {e.StackTrace}");
						}
						finally
						{
							semaphore.Release();
						}
					}
				});
			}

			// 等待所有任务完成
			while (semaphore.CurrentCount != mMemHack.MaxSearchThreadNum)
			{
				Thread.Sleep(1);
			}
			mMemHack.Searcher.ExitSearchBytes(searchBytes);

			List<long> result = searchRes.Where(addr => (ulong)addr >= startAddr && (ulong)addr <= endAddr).ToList();
			result.Sort();

			mMemHack.Log($"搜索耗时:{CommonUtils.DatetimeToTimespan(DateTime.Now) - startTime}ms, 共获取到{result.Count}个结果");

			return result.ToArray();
		}
	}

}
